<template>
  <div>
    <div class="columnTable">
      <div class="header">
        <slot name="title">
          <h4 v-if="title">{{ title }}</h4>
        </slot>
        <a
          v-if="showSetting"
          class="setting"
          @click="tableSettingVisible = true"
        >
          <SettingOutlined />
          <span class="setting-txt">字段设置</span>
        </a>
        <slot name="btns"></slot>
      </div>
      <a-table
        v-dragWidth="{ columns: tableColumns, id: tableName || 'columnTable' }"
        bordered
        size="small"
        :scroll="{ x, y }"
        :pagination="false"
        :row-key="
          rowKey ? rowKey : (r, index) => index + (tableName || 'columnTable')
        "
        :columns="tableColumns"
        :data-source="source"
        :row-selection="rowSelection"
      >
        <template
          v-for="item in columns.filter(_ => _.type)"
          :key="item.key"
          #[item.key]="{ record, index }"
        >
          <slot
            v-if="item.type === 'slot'"
            :record="record"
            :index="index"
            :name="item.key"
          />
          <!-- 清空按钮 -->
          <a-button
            v-if="item.type === 'reset' && !isTableDisabled && showAddBtn"
            type="primary"
            size="small"
            @click="operator('清空', index, record, item)"
          >
            清空
          </a-button>
          <!-- 图片预览 -->
          <template v-if="item.type === 'img'">
            <div class="img-list">
              <a-image
                width="50px"
                height="50px"
                :src="item.ossUrl"
                :key="i"
                v-for="(item, i) in record[item.key]"
              />
            </div>
          </template>
          <oss-upload
            v-if="item.type === 'ossUpload'"
            v-model:files="record[item.key]"
            small
            list-type="picture-card"
            :size="item.size || 20"
            :disabled="
              isTableDisabled ||
              isDisabled ||
              (item.setDisabled && item.setDisabled(record)) ||
              record.isdis
            "
            :limitNum="item.limitNum || 30"
            accept="png,jpg,jpeg,gif"
          ></oss-upload>
          <template v-if="!isTableDisabled">
            <a-textarea
              :class="renderError(record, item.key)"
              v-if="item.type === 'textarea'"
              v-model:value="record[item.key]"
              :max-length="item.maxLength || 100"
              :placeholder="item.title || item.placeholder"
              :rows="item.row || 1"
              :disabled="
                isDisabled ||
                (item.setDisabled && item.setDisabled(record)) ||
                record.isdis
              "
            />
            <a-input-number
              v-if="item.type === 'inputNumber'"
              v-model:value="record[item.key]"
              style="width: 100%"
              :min="item.min || 0"
              :max="item.max"
              :step="item.step || 1"
              :class="[renderError(record, item.key), item.class]"
              :formatter="
                item.formatter && (value => `${value}${item.formatter}`)
              "
              :parser="
                item.formatter &&
                (value => value.replace(`${item.formatter}`, ''))
              "
              :placeholder="item.title || item.placeholder"
              :precision="item.precision || 0"
              @change="val => changeInputNumber(val, item.key, index)"
              :disabled="
                isDisabled ||
                (item.setDisabled && item.setDisabled(record)) ||
                record.isdis
              "
            />
            <a-input
              :class="renderError(record, item.key)"
              v-if="
                item.type === 'input' ||
                (item.type === 'sel' && record.fillingType === 0)
              "
              v-model:value="record[item.key]"
              :placeholder="item.title || item.placeholder"
              :max-length="item.maxLength || 100"
              @change="e => changeInput(e, item.key, index, record)"
              :disabled="
                isDisabled ||
                (item.setDisabled && item.setDisabled(record)) ||
                record.isdis
              "
            />
            <a-date-picker
              v-if="item.type === 'date'"
              v-model:value="record[item.key]"
              allowClear
              size="small"
              class="width:100%"
              valueFormat="YYYY-MM-DD"
              :placeholder="item.title || item.placeholder"
            />
            <a-checkbox
              v-if="item.type === 'checkbox'"
              v-model:checked="record[item.key]"
              size="small"
              >{{ item.text }}</a-checkbox
            >
          </template>
          <template
            v-else-if="
              item.type === 'autoComplate' ||
              item.type === 'input' ||
              item.type === 'inputNumber' ||
              item.type === 'textarea'
            "
          >
            {{ record[item.key] }}
          </template>
          <template v-else-if="item.type === 'checkbox'">
            <a-checkbox
              disabled
              v-if="item.type === 'checkbox'"
              v-model:checked="record[item.key]"
              size="small"
              >{{ item.text }}</a-checkbox
            >
          </template>
          <!-- 下拉框 -->
          <a-select
            v-if="
              item.type === 'select' ||
              (item.type === 'sel' && record.fillingType === 1)
            "
            v-model:value="record[item.key]"
            allow-clear
            show-search
            class="preview"
            :mode="item.mode"
            :dropdown-style="dropdownStyle"
            :disabled="
              isTableDisabled ||
              isDisabled ||
              (item.setDisabled && item.setDisabled(record)) ||
              record.isdis
            "
            :class="renderError(record, item.key)"
            style="width: 100%"
            @dropdownVisibleChange="
              e => changeSelect(e, item.key, index, record, e)
            "
            @change="
              e => {
                changeSelect(e, item.key, index, record, true)
              }
            "
            :placeholder="item.title || item.placeholder"
            :maxTagCount="item.maxTagCount || 2"
          >
            <a-select-option
              v-for="v in record[item.key + 'List'] || item.options"
              :key="v.value"
              :disabled="v.disabled"
              :value="v.value"
            >
              {{ v.label }}
            </a-select-option>
          </a-select>
          <template
            v-if="
              item.type === 'action' &&
              !isDisabled &&
              !isTableDisabled &&
              !(item.setDisabled && item.setDisabled(record))
            "
          >
            <a-space
              ><a
                :disabled="record.isdis"
                v-for="key in item.btns"
                :key="key"
                @click="operator(key, index, record, item)"
                :class="
                  item.setDisabled && item.setDisabled(record) ? 'gray' : ''
                "
                >{{ key }}</a
              ></a-space
            >
          </template>
        </template>
      </a-table>

      <a-button
        v-if="showAddBtn && !isTableDisabled"
        style="margin-top: 8px"
        type="dashed"
        block
        size="small"
        @click="addLine"
      >
        <template #icon><PlusOutlined /></template>
        添加
      </a-button>
    </div>

    <tableSetting
      v-model:visible="tableSettingVisible"
      :localName="tableName"
      :columns="settingColumns"
      @reload="setColumns"
    />
  </div>
</template>

<script>
import { reactive, toRefs, watch, computed, ref } from 'vue'
import { SettingOutlined, PlusOutlined } from '@ant-design/icons-vue'
import tableSetting from './tableSetting.vue'
import { cloneDeep } from 'lodash-es'

export default {
  components: {
    SettingOutlined,
    PlusOutlined,
    tableSetting
  },
  props: {
    rowKey: {
      type: Function
    },
    isDisabled: {
      type: Boolean,
      default: false // 只
    },
    title: {
      type: String,
      default: ''
    },
    tableName: {
      type: String,
      default: ''
    },
    showSetting: {
      type: Boolean,
      default: false
    },
    source: {
      type: Array,
      default: () => []
    },
    columns: {
      type: Array,
      default: () => []
    },
    x: {
      type: [String, Number],
      default: '100%'
    },
    y: {
      type: [String, Number],
      default: '100%'
    },
    showAddBtn: {
      type: Boolean,
      default: true
    },
    rowSelectionEd: {
      type: Boolean,
      default: false
    },
    // 整个表格禁用
    disabled: {
      type: Boolean,
      default: false // 只
    },
    rules: {
      type: Object,
      default: () => {
        return {}
      }
    }
  },
  emits: ['changeInputNumber', 'addLine', 'operator', 'changeSelect'],
  setup(props, { emit }) {
    const isValid = ref(true)
    const state = reactive({
      dropdownStyle: {
        minWidth: 'max-content'
      },
      tableSettingVisible: false,
      tableColumns: [],
      settingColumns: [],
      selectedRows: [],
      propColumns: []
    })
    const isTableDisabled = computed(() => {
      return props.disabled
    })

    // onMounted(() => {
    //   initColumns()
    // })

    const initColumns = () => {
      state.settingColumns = cloneDeep(props.columns)

      state.propColumns.forEach(_ => {
        _.dataIndex = _.key
        _.type && (_.slots = { customRender: _.key })
        !_.align && (_.align = 'center')
        _.type === 'inputNumber' && (_.align = 'right')
      })

      setColumns()
    }

    const setColumns = () => {
      const data = JSON.parse(localStorage.getItem(props.tableName)) || []

      if (data?.length > 0) {
        const columns = []
        data.forEach(_ => {
          state.propColumns.forEach(item => {
            if (_ === item.title) {
              columns.push(item)
            }
          })
        })
        state.tableColumns = columns
      } else {
        state.tableColumns = state.propColumns
      }
    }

    const changeInput = (e, key, index, record) => {
      const val = e.target.value
      emit('changeInput', val, key, index, props.tableName, record)
    }

    const changeInputNumber = (val, key, index) => {
      emit('changeInputNumber', val, key, index, props.tableName)
    }

    const changeSelect = (e, key, index, record, open) => {
      emit('changeSelect', e, key, index, record, open)
    }

    const addLine = () => {
      emit('addLine', props.tableName)
    }

    const operator = (text, index, record, item) => {
      console.log(record, 'record')
      if (item && item.setDisabled && item.setDisabled(record)) return
      emit('operator', text, index, record, props.tableName, item)
    }
    const rowSelection = computed(() => {
      if (props.rowSelectionEd) {
        return {
          onChange: (selectedRowKeys, selectedRows) => {
            state.selectedRows = selectedRowKeys
            emit(
              'setSelectedRows',
              selectedRowKeys,
              selectedRows,
              props.tableName
            )
          },
          getCheckboxProps: record => ({
            disabled: record.noSelect
          })
        }
      } else {
        return null
      }
    })
    isValid.value = true
    const renderError = (row, key) => {
      let value = row[key],
        isRequired = false
      const rules = props.rules

      if (rules[key]) {
        if (typeof rules[key]?.required === 'function') {
          isRequired = rules[key]?.required(row)
        } else {
          isRequired = rules[key]?.required
        }
      }
      const isArray = typeof value === 'object' && Array.isArray(value)
      if (isArray) {
        value = row[key].length
      }
      if (!value && !isValid.value && isRequired) {
        return 'w100p has-error'
      }
      return 'w100p'
    }
    const getFieldRequired = (key, row) => {
      let isRequired = false
      const rules = props.rules
      if (rules[key]) {
        if (typeof rules[key]?.required === 'function') {
          isRequired = rules[key]?.required(row)
        } else {
          isRequired = rules[key]?.required
        }
      }
      return isRequired
    }
    /**
     * 验证行数据是否存在校验不通过
     * @param row
     */
    const handlerValidRule = row => {
      let noError = true
      const rules = props.rules || {}
      const keys = Object.keys(rules)
      keys.forEach(key => {
        const isRequired = getFieldRequired(key, row)
        if (isRequired && !row[key]) {
          noError = false
        }
      })
      return noError
    }
    const validFields = () =>
      new Promise(resolve => {
        const datas = props.source
        isValid.value = true

        datas.forEach(item => {
          const noError = handlerValidRule(item)
          if (!noError) {
            isValid.value = false
          }
        })
        resolve(isValid.value)
      })
    watch(
      () => props.columns,
      val => {
        state.propColumns = cloneDeep(val)
        initColumns()
      },
      {
        deep: true,
        immediate: true
      }
    )
    return {
      ...toRefs(state),
      setColumns,
      isTableDisabled,
      changeInput,
      changeInputNumber,
      changeSelect,
      addLine,
      operator,
      rowSelection,
      renderError,
      validFields
    }
  }
}
</script>
<style lang="scss" scoped>
.has-error {
  border: 1px solid red;
}
</style>
<style lang="sass" scoped>
.columnTable
  .header
    margin-bottom: 5px
    .setting
      display: inline-block
      padding: 2px 0
      .setting-txt
        margin-left: 7px
        font-size: 12px

.img-list :deep
  .ant-image
    margin-right: 10px
    cursor: pointer
    &:last-child
      margin-right: 0
  .ant-image-img
    padding: 2px
    border: 1px dashed #999

.operator-btns a
  margin-right: 8px
  &:last-child
    margin-right: 0
.gray
  color: rgba(0,0,0,.25)
  cursor: not-allowed
::v-deep .ant-select-disabled.ant-select-multiple .ant-select-selection-item
  border: none
  background: #fff
  color:#333
::v-deep .ant-checkbox-wrapper.ant-checkbox-wrapper-disabled span
  color:#333
</style>
